<!--
 * @Descripttion: (关系图)
 * @Author: (郭栋)
 * @Date: (2021-10-28)
 -->
<template>
  <!-- 画板 -->
    <div class="diagram-plus" style="overflow-x: hidden;overflow-y: hidden;">
    </div>
</template>

<script>
import * as d3 from 'd3'
import {commonJs} from '../common/common-js-topo'
import $ from 'jquery'

export default {
    name: "Diagram-plus",
    components: {},
    mixins: [commonJs],
    props: {},
    data() {
        return {
            // 超级DIV
            divSuper: void 0,
            svgWidth: '100%',
            svgHeight: '100%',
            // 树形布局之间的间隔
            widthTreesAll: 600,
            // svg画板参数
            svgParams: {},
            // SVG原型
            diagramPlus: void 0,
            // 画板元素存储
            svgElement: {
                links: [],
                nodes: [],
                paths: [],
            },
            // 画板元素模块
            svgEl: {
                link: void 0,
                node: void 0,
                path: void 0,
                linklabels: void 0,
                circleLink: void 0,
            },
            // 等离子原型
            simulation: void 0,
            // 节点的树形结构结果
            treeNodeList: void 0
        }
    },
    watch: {},
    computed: {},
    methods: {
        /**
         * 初始化画板初始化数据数据
         */
        initDiagramPlusOptions() {
            return {
                divClass: "diagram-plus",
                svgId: "svgPlus",
                width: this.svgWidth,
                height: this.svgHeight,
                fill: "#000000",
                call: d3.zoom().scaleExtent([0.01, 10]).extent([
                    [0, 0],
                    [500, 500]
                ]).on("zoom", (event) => {
                    this.diagramPlus.attr("transform", event.transform)
                }),
                dblclickZoom: null,
                contextmenu() {
                    d3.select('#btn_two').selectAll(".btn").style("background-color", "rgba(21, 69, 119, 0.74)").style("border-color", "#3c7ec1");
                    d3.select('#btn').selectAll(".btn").style("background-color", "rgba(21, 69, 119, 0.74)").style("border-color", "#3c7ec1");
                    d3.select('#btn').selectAll(".linetype").style("background-color", "rgba(21, 69, 119, 0.74)").style("border-color", "#3c7ec1");
                }
            }
        },
        /**
         * 初始化主模块
         */
        initDiagramPlus(options) {
            return d3.select("body")
                .selectAll("." + options.divClass)
                .append("svg")
                .attr("xmlns", "http://www.w3.org/1999/xhtml")
                .attr("id", options.svgId)
                .attr("width", options.width)
                .attr("height", options.height)
                .style("fill", options.bagColor)
                .call(options.call)
                .on("dblclick.zoom", function () {

                }).on("contextmenu", function () {
                    options.contextmenu();
                })
                .append("g")
                .attr('class', "all");
        },
        /**
         * 等离子孵化器
         */
        initSimulation() {
            return d3.forceSimulation(this.svgElement.nodes)
                //# link.id([id]) <>如果指定了 id 则将节点的 id 访问器设置为指定的函数并返回弹簧模型。如果 id 没有指定则返回当前的节点 id 访问器，默认为数值类型的节点索引 node.index:
                .force("link", d3.forceLink(this.svgElement.links).id(function (d) {
                    return d.S_KEY;
                }))
                //创建一个使用默认参数的电荷力模型。若强度为正值则表示节点之间相互吸引，负值表示节点之间相互排斥。
                .force("charge", d3.forceManyBody().strength(-400))
                .force("center", d3.forceCenter(0, 0))
                .force("x", d3.forceX(this.svgWidth / 2).strength(1))
                .force("y", d3.forceY(this.svgHeight / 2).strength(1))
                // 等离子内部元素离散计算
                .on("tick", this.tickHandle);
        },
        /**
         * 重启等离子孵化器
         */
        restartSimulation() {
            this.simulation.stop();
            this.simulation.nodes(this.svgElement.nodes);
            //distance 设置线的距离
            this.simulation.force("link").links(this.svgElement.links).distance(150);
            this.simulation.alpha(1);
            this.simulation.restart();
        },
        /**
         * 等离子内部元素离散计算
         */
        tickHandle() {
            this.svgEl.link.attr("x1", function (d) {
                return d.source.x;
            })
                .attr("y1", function (d) {
                    return d.source.y;
                })
                .attr("x2", function (d) {
                    return d.target.x;
                })
                .attr("y2", function (d) {
                    return d.target.y;
                });

            this.svgEl.path.attr("d", function (d) {
                    return "M" +
                        d.source.x + "," +
                        d.source.y + "L" +
                        (d.target.x) + "," +
                        (d.target.y)
                }
            );

            this.svgEl.node.attr("transform", function (d) {
                // if(!isFinite(d.x) || !isFinite(d.x)){
                //     return "translate(" + 0 + "," + 0 + ")";
                // }
                return "translate(" + d.x + "," + d.y + ")";
            });
        },
        canvasMarker() {
            //1 先绘制一个箭头，这里force_svg就是在body中添加的svg。start
            this.diagramPlus.append('defs')
                .append('marker')
                .attr('id', 'start')
                .attr("viewBox", "0 -5 10 10")
                .attr('refX', -15)
                .attr('refY', 0)
                .attr('orient', 'auto')//绘制方向，可设定为：auto（自动确认方向）和 角度值
                .attr('markerWidth', 10)
                .attr('markerHeight', 10)
                .attr("markerUnits", "userSpaceOnUse") //最后一个属性是markerUNits，用于确定marker是否进行缩放.
                .attr('xoverflow', 'visible')
                .append('svg:path')
                .attr('d', 'M10,-5L0,0L10,5')//箭头的路径
                .attr('fill', '#2cf4fa');

            //2 先绘制一个箭头，这里force_svg就是在body中添加的svg。end
            this.diagramPlus.append('defs')
                .append('marker')
                .attr('id', 'end')
                .attr("viewBox", "0 -5 10 10")
                .attr('refX', 25)
                .attr('refY', 0)
                .attr('orient', 'auto')
                .attr('markerWidth', 10)
                .attr('markerHeight', 10)
                .attr("markerUnits", "userSpaceOnUse") //最后一个属性是markerUNits，用于确定marker是否进行缩放.
                .attr('xoverflow', 'visible')
                .append('svg:path')
                .attr('d', 'M0,-5L10,0L0,5')
                .attr('fill', '#2cf4fa');
        },
        /**
         * 添加对应的元素组模块（也就是页面每种元素的模块）
         * 这里的先后顺序会影响覆盖层的层级
         */
        addSvgGroup() {
            this.diagramPlus.append("g").attr("id", "path_group");
            this.diagramPlus.append("g").attr("id", "link_group");
            this.diagramPlus.append("g").attr("id", "circle_link");
            this.diagramPlus.append("g").attr("id", "node_group");
            this.diagramPlus.append("g").attr("id", "lable_group");

            this.svgEl.path = this.diagramPlus.select("#path_group").selectAll(".path");
            this.svgEl.node = this.diagramPlus.select("#node_group").selectAll(".node");
            this.svgEl.circleLink = this.diagramPlus.select("#circle_link").selectAll(".circle");
            this.svgEl.link = this.diagramPlus.select("#link_group").selectAll(".link");
            this.svgEl.linklabels = this.diagramPlus.select("#lable_group").selectAll(".lable");
        },
        /**
         * 添加节点元素方法
         */
        addNodeElement() {
            let that = this
            this.svgEl.node = this.svgEl.node.data(this.svgElement.nodes);
            this.svgEl.node.exit().remove(); //exit 选择集通常用来移除多余的元素。  remove 移除old绑定的元素:
            let nodeEnter = this.svgEl.node.enter()
                .append("g")
                .attr("class", "node")
                .attr("id", function (d) { //添加ID
                    return "node-" + d.S_KEY;
                })
                .attr("transform", function (d) { //添加ID
                    return "translate(" + d.tx + "," + d.ty + ")";
                })
                .on("mouseover", function () {
                    d3.select(this).select("text").transition()
                        .duration(200)
                        .attr("dy", "-30px")
                        .attr("text-anchor", "middle")
                        .attr("fill", "#5bc0de");
                }).on("mouseout", function () {
                    d3.select(this).select("text").transition()
                        .duration(200)
                        .attr("dy", "30px")
                        .attr("text-anchor", "middle")
                        .attr("fill", "#5bc0de");
                    //鼠标移开到节点，改变连接线的颜色
                    d3.selectAll(".link").each(function (nodeItem) {
                        if (nodeItem) {
                            d3.select(this).style("stroke", nodeItem.linkColor);
                        }
                    })
                }).on("click.select", function (event, d) {
                    if (event.defaultPrevented) return;
                    console.log(d)
                    that.delCircleElement()
                    that.addCircleElement(nodeEnter)
                    that.$bus.emit("assignmentFormNode", {param: d, typeDetail: 1})
                }).on("dblclick.select", function (event) {
                    if (event.defaultPrevented) return;
                    d3.select(this).select(".icon").attr("xlink:href", function (d) {
                        if (d.type === 'js') return `./images/${d.type}.png`
                        d.type = d.type === 'huo' ? 'qie' : 'huo'
                        return `./images/${d.type}.png`;
                    });
                })
                //拖动节点事件绑定。
                .call(d3.drag()
                    .subject(this.dragsubject)
                    .on("start", this.dragStarted)
                    .on("drag", this.dragGed)
                    .on("end", this.dragEnded));

            nodeEnter.append("text")
                //文字不能被选中，因为会影响添加线条功能
                .attr("class", "noselect")
                .attr("dy", "35px")
                .attr("text-anchor", "middle")
                .attr("fill", "#5bc0de")
                .text(function (d) {
                    return d.S_NAME;
                });

            nodeEnter.append("image")
                .attr("class", "icon")
                .attr("xlink:href", function (d) {
                    return `./images/${d.type}.png`;
                })
                .attr("x", -16)
                .attr("y", -16)
                .attr("width", 32)
                .attr("height", 32);

            this.svgEl.node = nodeEnter.merge(this.svgEl.node);
            this.restartSimulation();
        },
        /**
         * 更新构造节点元素
         */
        updateNodeElement() {
            let keyLinks = this.svgElement.links.map((item) => {
                let {source: {S_KEY: sKey}} = item
                return sKey
            })
            this.svgEl.node.select(".icon").attr("xlink:href", function (d) {
                if (keyLinks.includes(d.S_KEY)) d.type = 'qie'
                return `./images/${d.type}.png`;
            });
            this.svgEl.node.select("text").text(function (d) {
                if (keyLinks.includes(d.S_KEY)) d.S_NAME = ''
                return d.S_NAME
            });
        },
        /**
         * 清除节点元素的动态圈
         */
        delCircleElement() {
            d3.selectAll(".circle-select").remove()
        },
        /**
         * 构造节点元素的动态圈
         */
        addCircleElement(nodeEnter) {
            nodeEnter.append("circle")
                .attr("class", "circle-select")
                .style("fill", "none")
                .attr("r", 17)
                .style("pointer-events", "none") //鼠标事件拜拜
                .style("stroke-width", "3")
                .style("stroke", () => {
                    return "#0095ff";
                })
                .style("opacity", () => {
                    return 1;
                }).transition()
                .duration(function (d) {
                    return d.time;
                })
                .delay(function (d, i) {
                    if (i) {
                        return i * 10;
                    }
                    return 10;
                })
                .on("start", function repeat() {
                    d3.active(this)
                        .attr("r", 17)
                        .style("opacity", 1)
                        .transition()
                        .attr("r", 50)
                        .style("opacity", 0)
                        .transition()
                        .on("start", repeat);
                });
        },
        /**
         * 构造线条
         */
        addLinkElement() {
            let that = this
            //link
            this.svgEl.link = this.svgEl.link.data(this.svgElement.links);
            this.svgEl.link.exit().remove();
            //2 添加连线并和箭头组合在一起,这里link的data已经设置了。
            let linkEnter = this.svgEl.link
                .enter()
                .append("line")
                // 虚线样式
                .attr("class", function (d) {
                    return "link " + d.S_REL_TYPE_LINK
                })
                .attr("id", function (d, i) {
                    return 'line' + i
                })
                // 绑定结束箭头和线
                .attr('marker-end', () => {
                    return 'url(#end)'
                })
                // 绑定开始箭头和线
                // .attr('marker-start', () => {
                //   return 'url(#start)'
                // })
                .style("stroke", function (d) {
                    return d.linkColor
                })
                //线条粗细
                .style("stroke-width", 5)
                .on("mouseover", function () {
                    d3.select(this).style("stroke", "#0095ff");
                }).on("mouseout", function () {
                    d3.select(this).style("stroke", "#5bdebf");
                })
                .on("click.select.link", function (d) {
                    if (d3.event.defaultPrevented) return;
                    console.log(d)
                    let link = that.svgElement.links.filter((item) => item.S_REL_KEY === d.S_REL_KEY)
                    that.addCircleLinkElement(link)
                    that.$bus.emit("assignmentFormLink", {param: d, typeDetail: 2})
                })
            this.svgEl.link = linkEnter.merge(this.svgEl.link);

            this.svgEl.path = this.svgEl.path.data(this.svgElement.links);
            this.svgEl.path.exit().remove();
            let pathEnter = this.svgEl.path.enter().append('path').attr('class', 'path')
                .attr('fill-opacity', 0)
                .attr('stroke-opacity', 0)
                .attr('fill', 'blue')
                .attr('stroke', 'red')
                .attr('id', function (d, i) {
                    return 'link' + i
                })
                .style("pointer-events", "none");
            this.svgEl.path = pathEnter.merge(this.svgEl.path);

            this.svgEl.linklabels = this.svgEl.linklabels.data(this.svgElement.links);
            this.svgEl.linklabels.exit().remove();
            let linklabelsEnter = this.svgEl.linklabels.enter().append('text')
                .attr("class", "lable")
                .attr('id', function (d, i) {
                    return 'linklable' + i
                })
                .attr('dy', 15)
                .attr('dx', 50)
                .attr('font-size', 14)
                .attr('fill', '#aaa')

            linklabelsEnter.append('textPath')
                .attr('xlink:href', function (d, i) {
                    return '#link' + i
                })
                .text(function (d) {
                    return d.S_REL_NAME;
                });

            this.svgEl.linklabels = linklabelsEnter.merge(this.svgEl.linklabels);
            this.svgEl.link = linkEnter.merge(this.svgEl.link);
            // this.restartSimulation()
        },
        /**
         * 更新构造links
         */
        updateLinkElement() {
            this.svgEl.link
                // 虚线样式
                .attr("class", function (d) {
                    return "link " + d.S_REL_TYPE_LINK
                })

            this.svgEl.linklabels.select("textPath")
                .attr('xlink:href', function (d, i) {
                    return '#link' + i
                })
                .text(function (d) {
                    return d.S_REL_NAME
                });
        },
        /**
         * 构造-link动态连接效果
         */
        addCircleLinkElement(links) {
            let that = this
            this.svgEl.circleLink = this.svgEl.circleLink.data(links);
            this.svgEl.circleLink.exit().remove();
            let circle = this.svgEl.circleLink.enter()
                .append("circle")
                .attr('class', 'circle-link')
                .classed("c", true)
                .attr("r", function () {
                    return 5
                })
                .attr("fill", "rgba(255, 120, 0, 1)")
                .attr("transform", function () {
                    return "translate(" + 100 + "," + 100 + ")"
                });

            d3.selectAll(".circle-link")
                .attr("transform", function (d) {
                    "translate(" + d.source.x + "," + d.source.y + ")"
                })
                .transition()
                .ease(d3.easeCircleInOut)
                .delay(0)
                .duration(3000)
                .on("start", function repeat() {
                    d3.active(this)
                        .attrTween("transform", function (d) {
                            let path = that.svgEl.link._groups[0][d.index];
                            let l = path.getTotalLength();
                            return function (t) {
                                var p = path.getPointAtLength(t * l);
                                return "translate(" + p.x + "," + p.y + ")"
                            }
                        })
                        .transition()
                        .on("start", repeat);
                });

            this.svgEl.circleLink = circle.merge(this.svgEl.circleLink);
        },
        /**
         * 清除构造link动态连线
         */
        delCircleLinkElement() {
            d3.selectAll(".circle-link").remove()
        },
        /**
         * 绑定联线方法
         */
        bindAddLinkEvent() {
            let that = this
            //保证节点不能拖动
            this.svgEl.node.on(".drag", null);
            let mousedownNode = void 0,
                mouseupNode = void 0;
            let dragLine;
            this.svgEl.node.on("mousedown.add-link", function (event, d) {
                dragLine = that.diagramPlus.append("line").attr("class", "linkd").style("stroke", "#5bc0de");
                mousedownNode = d;
                dragLine.attr("class", "linkd").attr('marker-end', 'url(#end)').style("stroke-width", 3).lower().attr("x1", d["x"]).attr("y1", d["y"]).attr("x2", d["x"]).attr("y2", d["y"]);
                event.stopPropagation();
            }).on("mouseup.add-link", function (event, d) {
                d3.selectAll('.linkd').remove();
                mouseupNode = d;
                if (!mousedownNode || mouseupNode === mousedownNode) {
                    mousedownNode = void 0;
                    mouseupNode = void 0;
                    return;
                }
                let _link = {
                    S_REL_CODE: Math.random(),
                    I_ARROW: 1,
                    S_REL_TYPE_LINK: '',
                    S_REL_NAME: '',
                    S_REL_KEY: Math.random(),
                    linkColor: "#5bdebf",
                    source: mousedownNode.S_KEY,
                    sourceTable: mousedownNode.node_node_type,
                    target: mouseupNode.S_KEY,
                    targetTable: mouseupNode.node_node_type,
                };

                let hasLink = that.svgElement.links.findIndex(function (linkItem) {
                    return linkItem.source.S_KEY == mousedownNode.S_KEY && linkItem.target.S_KEY == mouseupNode.S_KEY;
                }) > -1;
                let hasOppositeLink = that.svgElement.links.findIndex(function (linkItem) {
                    return linkItem.source.S_KEY == mouseupNode.S_KEY && linkItem.target.S_KEY == mousedownNode.S_KEY;
                }) > -1;
                if (!hasLink) {
                    //如果是反向边 则合并为一条双向边
                    if (hasOppositeLink) {
                        that.svgElement.links.forEach(function (linkItem) {
                            linkItem.source.S_KEY == mouseupNode.S_KEY && linkItem.target.S_KEY == mousedownNode.S_KEY && (linkItem["isTwoWay"] = true);
                        });
                    } else {
                        that.svgElement.links.push(_link)
                        that.addLinkElement()
                        that.updateNodeElement()
                    }
                } else {
                    that.$message({
                        message: '已经有连线了，不能重复添加！',
                        type: 'warning',
                    })
                }
            });

            d3.select(".diagram-plus").on("mousedown.add-link", function () {
                if (!mousedownNode) return;
            }).on('mousemove.add-link', function (event) {
                if (!mousedownNode) return;

                let _util$getTranslateAnd = that.getTranslateAndScale(),
                    translate = _util$getTranslateAnd.translate,
                    scale = _util$getTranslateAnd.scale;
                let _d3$mouse3 = d3.pointer(event),
                    _d3$mouse4 = that._slicedToArray(_d3$mouse3, 2),
                    x = _d3$mouse4[0],
                    y = _d3$mouse4[1];

                dragLine.attr("x1", mousedownNode["x"]).attr("y1", mousedownNode["y"]).attr("x2", "" + (x / scale - +translate[0] / scale)).attr("y2", "" + (y / scale - +translate[1] / scale));
                event.preventDefault();
            }).on("mouseup.add-link", function () {
                if (mousedownNode) {
                    d3.selectAll('.linkd').remove();
                }
                mousedownNode = null;
                mouseupNode = null;
            });
        },
        /**
         * 不固定节点的方法
         */
        nodeFxFyNull() {
            //v4版本的api对fixed节点的规定是 如果节点数据(d) 有fx fy两个值不为null，那么就是固定节点，不固定节点的方法就是 设置fx fy=null。
            d3.selectAll(".node").each(function (nodeItem) {
                nodeItem.fx = null;
                nodeItem.fy = null;
            });
        },
        /**
         * 绑定全局事件
         */
        bindEventAll() {
            let that = this
            // 快捷键绑定
            document.onkeydown = function () {
                let key = window.event.keyCode;
                if (key === 49) {
                    that.relieveAll()
                    that.$bus.emit("bindAddNodeEvent")
                    console.log('添加节点')
                } else if (key === 50) {
                    that.relieveAll()
                    that.bindAddLinkEvent()
                    console.log('添加连线');
                }
            }
            //这一步是为了阻止右击时系统默认的弹出框
            document.getElementById("svgPlus").oncontextmenu = function (e) {
                e.preventDefault();
            };
            //在这里你就可以自己定义事件的函数啦
            document.getElementById("svgPlus").onmouseup = function (oEvent) {
                if (!oEvent) oEvent = window.event;
                // ==2，鼠标右击事件
                if (oEvent.button == 2) {
                    that.relieveAll()
                }
            }
        },
        /**
         * 树表达式生成
         */
        treeConditionalExpressions(chieftainId) {
            let middleData = {};
            let linksBak = [...this.svgElement.links];
            let nodesBak = [...this.svgElement.nodes];
            nodesBak.forEach((d) => {
                if (d.S_KEY == chieftainId) { //头目ID入口
                    let temp = {
                        name: d.S_KEY,
                        children: []
                    };
                    let treeData = this.toTreeData(linksBak, d);
                    temp.children = treeData;
                    middleData = temp;
                }
            });
            let tree = this.svgElement.nodes.find((item) => {
                return item.S_KEY === middleData.name
            })
            let str = this.expressionRecursion(middleData.children, tree.type)
            console.log(str)
        },
        /**
         * 表达式递归
         * @param children 子节点
         * @param type 父节点类型
         * @returns {string} 返回凭借表达式
         */
        expressionRecursion(children, type) {
            let str = ''
            children.forEach((itemChildren, index) => {
                let tree = this.svgElement.nodes.find((item) => {
                    return item.S_KEY === itemChildren.name
                })
                if (itemChildren.children.length > 0) {
                    str += ` ${index === 0 ? '' : this.conditionalJudgment(type)} (${this.expressionRecursion(itemChildren.children, tree.type)} )`
                } else {
                    str += ` ${index === 0 ? '' : this.conditionalJudgment(type)} ${tree.S_NAME}`
                }
            })
            return str
        },
        /**
         * 是且是或判断
         * @param type 节点类型
         * @returns {string}
         */
        conditionalJudgment(type) {
            return type === 'qie' ? '&&' : '||'
        },
        /**
         * 树形结构生成
         * @param chieftainId 树根节点ID
         * @param currentIndex 当前第几个树
         * @param count 一共几棵树
         */
        drawTree(chieftainId, currentIndex, count) {
            let middleData = {};
            let linksBak = [...this.svgElement.links];
            let nodesBak = [...this.svgElement.nodes];
            nodesBak.forEach((d) => {
                if (d.S_KEY == chieftainId) { //头目ID入口
                    let temp = {
                        name: d.S_KEY,
                        children: []
                    };
                    let treeData = this.toTreeData(linksBak, d);
                    temp.children = treeData;
                    middleData = temp;
                }
            });
            //创建一个hierarchy layout
            let hierarchyData = d3.hierarchy(middleData)
                .sum(function (d) {
                    return d.value;
                });
            let countNode = nodesBak.length
            let xDepth = countNode > 10 ? countNode * 50 : 600
            let yDepth = countNode > 10 ? countNode * 60 : 600
            let tree = d3.tree().size([xDepth, yDepth]).separation((a, b) => (a.parent == b.parent ? 1 : 2) / a.depth); //设置树的大小、间隔距离
            let treeData = tree(hierarchyData);
            let note_tree = treeData.descendants();
            this.treeLayout(note_tree, currentIndex, count);
        },
        treeLayout(note_tree, currentIndex, count) {
            let zonglength = 2 * (count) * this.widthTreesAll;
            let tou = $('.diagram-plus').width() / 2 - (zonglength / 2); //按照中心，计算出对称的起点。
            if (this.svgElement.nodes.length) {
                let centerPoint = 0;
                if (count > 1) {
                    centerPoint = [currentIndex == 0 ? tou : tou + this.widthTreesAll * (2 * currentIndex), 50];
                } else {
                    centerPoint = [$('.diagram-plus').width() / 2 - note_tree[0].x, 50];
                }
                let endCordinates = {};
                note_tree.forEach((d) => {
                    endCordinates[d.data.name] = {
                        x: d.x + centerPoint[0],
                        y: d.y + centerPoint[1]
                    };
                });
                this.initAnimateTree(endCordinates);
            }
        },
        initAnimateTree(endCordinates) {
            let circleLayoutTimer = void 0;
            d3.selectAll(".node").each(function (nodeItem) {
                if (endCordinates[nodeItem.S_KEY]) {
                    d3.select(this).transition().duration(700).ease(d3.easeCircleInOut).attr("transform", "translate(" + endCordinates[nodeItem.S_KEY].x + "," + endCordinates[nodeItem.S_KEY].y + ")");
                }
            });
            d3.selectAll(".link").each(function (nodeItem) {
                if (nodeItem && endCordinates[nodeItem.source.S_KEY] && endCordinates[nodeItem.target.S_KEY]) {
                    d3.select(this).transition().duration(700).ease(d3.easeCircleInOut).attr('x1', endCordinates[nodeItem.source.S_KEY].x).attr('y1', endCordinates[nodeItem.source.S_KEY].y).attr('x2', endCordinates[nodeItem.target.S_KEY].x).attr('y2', endCordinates[nodeItem.target.S_KEY].y);
                }
            });
            circleLayoutTimer && clearTimeout(circleLayoutTimer);
            circleLayoutTimer = setTimeout(() => {
                d3.selectAll(".node").each((nodeItem) => {
                    if (endCordinates[nodeItem.S_KEY]) {
                        nodeItem.x = endCordinates[nodeItem.S_KEY].x;
                        nodeItem.y = endCordinates[nodeItem.S_KEY].y;
                        nodeItem.fx = nodeItem.x;
                        nodeItem.fy = nodeItem.y;
                    }
                });
                this.autoZoom();
                // 重新绘制svg
                this.showForce();
            }, 350);
        },
        showForce() {
            this.addNodeElement()
            this.addLinkElement()
        },
    },
    created() {

    },
    mounted() {
        this.divSuper = d3.select("body").append("div")
            .attr("class", "tooltip")
            .style("opacity", 0);
        let options = this.initDiagramPlusOptions()
        this.diagramPlus = this.initDiagramPlus(options)
        this.simulation = this.initSimulation()
        this.simulation.stop()
        this.canvasMarker()
        this.addSvgGroup()
        this.nodeFxFyNull()
        this.bindEventAll()
        for (let i = 0; i < 0; i++) {
            this.svgElement.nodes.push({
                S_NAME: i,
                S_KEY: i,
                type: 'js',
                time: 800
            })
        }
        this.addNodeElement()
        this.$bus.on("addNode", (node_n) => {
            this.svgElement.nodes.push(node_n)
            this.addNodeElement()
        })
        this.$bus.on("bindAddLinkEvent", () => {
            this.bindAddLinkEvent()
        })
        this.$bus.on("treeGo", (type) => {
            let keyLinks = this.svgElement.links.map((item) => {
                let {target: {S_KEY}} = item
                return S_KEY
            })
            let treeTheLeader = this.svgElement.nodes.filter((item) => {
                return !keyLinks.includes(item.S_KEY)
            })
            let count = treeTheLeader.length;
            treeTheLeader.forEach((d, i) => {
                this[type](d.S_KEY, i, count)
            })
        })
        this.$bus.on("updateLinkElement", () => {
            this.updateLinkElement()
        })
        this.$bus.on("updateNodeElement", () => {
            this.updateNodeElement()
        })
    },
}
</script>

<style>
.dashed-line {
    stroke-dasharray: 10, 10;
    stroke-dashoffset: 10;
    -webkit-animation: draw 0s ease 1;
}

div.tooltip {
    position: absolute;
    text-align: center;
    width: 300px;
    height: auto;
    padding: 2px;
    font: 12px sans-serif;
    background: lightsteelblue;
    border: 0;
    border-radius: 8px;
    pointer-events: none;
}

</style>
